
use chrono::prelude::*;

use async_graphql::{Error, ErrorExtensions};
use rbatis::crud::{Skip, CRUD};
use rbatis::rbatis::Rbatis;

use crate::dbs::sqlite::Peer;
use crate::features::ddd::Aggregate;
use crate::features::events::{self, modelsdbo::Event};
use crate::features::quizzes::ddd::QuizEvent;
use crate::features::quizzes::ddd::{QuizAggregate, QuizSnapshot,QuizConfig,QuizItemConfig};
use crate::features::quizzes::modelsdbo::{QuizDBO, QuizItemDBO};
use crate::features::quizzes::modelsgqo::{NewQuiz, Quiz, QuizItem};
use crate::features::quizzes::repository::{self};
use crate::features::sgraph::{self, modelsdbo::EdgeDBO};
use crate::util::constant::GqlResult;

// 查询所有试卷Quiz
pub async fn all_quizzes(my_peer: &Peer, rbatis_pool: &Rbatis) -> GqlResult<Vec<Quiz>> {
  let rs_db = rbatis_pool.fetch_list::<QuizDBO>().await;

  if rs_db.is_ok() {
    let quiz_dbos = rs_db.unwrap();
    let quiz_gqos: Vec<Quiz> = quiz_dbos
      .into_iter()
      .map(|x| {
        let mut x1: Quiz = x.clone().into();
        match x.m3u8 {
          Some(v) => x1.m3u8 = Some(format!("{}{}", my_peer.data_dir, v)),
          _ => {}
        }
        x1
      })
      .collect();

    Ok(quiz_gqos)
  } else {
    Err(Error::new("1-all-quizs").extend_with(|_, e| e.set("details", "Database Error")))
  }
}

/// select quiz item members of quiz identified by quiz_id
pub async fn get_quizitem_members_of(rbatis_pool: &Rbatis, quiz_id: &str) -> Vec<QuizItemDBO> {
  let result = repository::select_quiz_items_by(rbatis_pool, quiz_id).await;
  match result {
    Ok(v) => match v {
      Some(vv) => vv,
      _ => vec![],
    },
    _ => vec![],
  }
}

//批量-查询id
pub async fn get_quiz_items_by_ids(
  rbatis_pool: &Rbatis,
  ids: &Vec<String>,
) -> Result<Vec<QuizItemDBO>, rbatis::Error> {
  rbatis_pool.fetch_list_by_column("id", ids).await
}

// 插入新试卷Quiz
pub async fn new_quiz(
  rbatis_pool: &Rbatis,
  mut new_quiz: NewQuiz,
) -> Result<QuizDBO, rbatis::Error> {
  new_quiz.id = new_quiz.id.to_lowercase();

  if repository::get_quiz_by_id(rbatis_pool, &new_quiz.id)
    .await
    .is_ok()
  {
    Err(rbatis::Error::from("id 已存在"))
  } else {
    let now: DateTime<Utc> = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z`

    //rbatis_pool
    //  .save(&new_quiz,&[])
    //  .await
    //  .expect("插入 quiz 数据时出错");

    repository::get_quiz_by_id(rbatis_pool, &new_quiz.id).await
  }
}

// 查询所有试题QuizItem
pub async fn all_quizitems(rbatis_pool: &Rbatis) -> GqlResult<Vec<QuizItem>> {
  let quiz_item_dbos = rbatis_pool.fetch_list::<QuizItemDBO>().await.unwrap();

  if quiz_item_dbos.len() > 0 {
    let quiz_item_gqos: Vec<QuizItem> = quiz_item_dbos.into_iter().map(|x| x.into()).collect();

    Ok(quiz_item_gqos)
  } else {
    Err(Error::new("1-all-quizs").extend_with(|_, e| e.set("details", "No records")))
  }
}

///  add quiz to my tasks 试卷加入我的EBP清单
pub async fn add_ebp_quizitems_to_tasks(
  rbatis_pool: &Rbatis,
  my_peer: &Peer,
  quiz_id: &str,
) -> Result<QuizDBO, rbatis::Error> {
  let db_result = repository::get_quiz_by_id(rbatis_pool, quiz_id).await;
  // found
  if db_result.is_ok() {
    let mut quiz_dbo = db_result.unwrap();
    let quiz_item_dbos = repository::select_quiz_items_by(rbatis_pool, quiz_id).await;
    let mut quiz_items: Vec<QuizItemDBO> = vec![];
    if quiz_item_dbos.is_ok() {
      match quiz_item_dbos.unwrap() {
        Some(mut v) => {
          v.retain(|x| x.is_master == Some(0));
          quiz_items = v
        }
        _ => {}
      }
    }

    let mut quiz_agg = QuizAggregate::init(
      &QuizSnapshot {
        quiz: quiz_dbo.to_owned(),
        quiz_items: quiz_items,
        ..Default::default()
      },
      &Vec::new(),
      &QuizConfig{
        ..Default::default()
      }

    );

    let rs_events = quiz_agg.create_task(my_peer, &quiz_dbo.subject);
    if rs_events.is_ok() {
      let quiz_events = rs_events.unwrap();
      for evt in quiz_events {
        // 1.save event first
        let rs_evt_dbo =
          events::services::append(rbatis_pool, my_peer, quiz_id, &Event::Quiz(evt.to_owned()))
            .await;
        // 2. apply event to aggregate
        quiz_agg = quiz_agg.apply(&evt);
      }
      // 3. finally upsert snapshot
      let upserted = repository::upsert_snapshot(rbatis_pool, quiz_agg.get_snapshot()).await;
      println!("upsert_snapshot upserted={:?}", upserted);

      Ok(quiz_agg.get_snapshot().quiz.to_owned())
    } else {
      Err(rbatis::Error::E(format!(
        "Failed to create task for quiz.id={}",
        quiz_id
      )))
    }
  } else {
    Err(rbatis::Error::E(format!(
      "Not found quiz for id={}",
      quiz_id
    )))
  }
}

// 通过 id 获取试题QuizItem
pub async fn find_user_quiz_ebp_info(
  rbatis_pool: &Rbatis,
  quiz_id: &str,
  user_id: &str,
) -> Result<EdgeDBO, rbatis::Error> {
  let edge_dbo = sgraph::services::find_edge(rbatis_pool, user_id, "tester", quiz_id).await;

  edge_dbo
}
